package com.lovely3x.jobservice;

import android.app.Notification;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import com.lovely3x.common.utils.ALog;
import com.lovely3x.jobservice.task.Progress;
import com.lovely3x.jobservice.task.Task;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * 工作服务管理器
 * 简化直接操作JobService的繁琐
 * Created by lovely3x on 16-1-31.
 */
public class JobServiceManager {

    static final ConcurrentLinkedQueue<JobServiceListener> mJobServiceListeners = new ConcurrentLinkedQueue<>();
    private static final JobServiceManager INSTANCE = new JobServiceManager();
    private static final boolean DEBUG = false;
    private static Context mContext;
    private static Receiver mReceiver;
    /**
     * 服务是否创建成功
     */
    private static boolean mJobServiceCreated;
    /**
     * 是否自动发布进度
     */
    private static boolean mAutoPublish;


    /*接收器的权限,防止多应用广播冲突*/
    public static final String RECEIVER_PERMISSION = BuildConfig.RECEIVER_PERMISSION;


    /**
     * 等待队列
     */
    private final LinkedList<Runnable> eventQueue = new LinkedList<>();

    private JobServiceManager() {
    }

    public static JobServiceManager getInstance() {
        return INSTANCE;
    }

    /**
     * 当前的状态是否已经是自动发布进度
     *
     * @return true or false
     */
    public boolean isAutoPublish() {
        return mAutoPublish;
    }

    /**
     * 查看当前工作服务是否已经创建
     *
     * @return true or false
     * @throws IllegalStateException 当尚未初始化抛出此异常
     */
    public boolean jobServiceIsCreated() {
        initChecker();
        return mJobServiceCreated;
    }

    /**
     * 异步初始化
     * 初始化主要用于启动服务
     *
     * @param context 上下文
     */
    public void init(Context context) {
        if (context == null) throw new IllegalArgumentException("Context con not be null");
        if (!mJobServiceCreated) {
            mContext = context.getApplicationContext() == null ? context : context.getApplicationContext();
            registerReceiver();

            Intent intent = getIntent();
            mContext.startService(intent);

            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_CREATE_SERVICE_IF_NEED);
            mContext.startService(serviceIntent);
        } else {
            synchronized (mJobServiceListeners) {
                for (JobServiceListener listener : mJobServiceListeners)
                    listener.onServiceInitialized();
            }
        }
    }

    /**
     * 停止服务
     */
    public void stopService() {
        Intent serviceIntent = getIntent();
        serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_STOP_SERVICE);
        mContext.startService(serviceIntent);
    }

    /**
     * 注册服务接收器
     */
    void registerReceiver() {
        //Register receiver
        initChecker();
        mReceiver = new Receiver();
        IntentFilter filters = new IntentFilter();
        filters.addAction(JobService.BROAD_ACTION_TASK_LIST);
        filters.addAction(JobService.BROAD_ACTION_PROGRESS);
        filters.addAction(JobService.BROAD_ACTION_REMOVE_RESULT);
        filters.addAction(JobService.BROAD_ACTION_SERVICE_CREATED);
        filters.addAction(JobService.BROAD_ACTION_SERVICE_DESTROYED);
        filters.addAction(JobService.BROAD_ACTION_SERVICE_INITIALIZED);
        filters.addAction(JobService.BROAD_ACTION_PAUSE_TASK_RESULT);
        filters.addAction(JobService.BROAD_ACTION_RESUME_RESULT);
        filters.addAction(JobService.BROAD_ACTION_TASK_EXECUTED);
        mContext.registerReceiver(mReceiver, filters,RECEIVER_PERMISSION,null);
    }

    /**
     * 解除广播接收器
     */
    void unregisterReceiver() {
        //Unregister receiver
        initChecker();
        if (mReceiver != null) mContext.unregisterReceiver(mReceiver);
    }

    /**
     * 初始化检查
     */
    void initChecker() {
        if (mContext == null) throw new IllegalStateException("Must be initialized before use.");
    }

    /**
     * 注册工作服务监听器
     *
     * @param listener 需要注册的监听器对象
     */
    public void registerJobServiceListener(JobServiceListener listener) {
        if (listener == null) throw new IllegalArgumentException();
        synchronized (mJobServiceListeners) {
            mJobServiceListeners.add(listener);
        }
    }

    /**
     * 解除注册的工作服务监听器
     *
     * @param listener 需要解除的监听i去对象
     */
    public void unregisterJobServiceListener(JobServiceListener listener) {
        if (listener == null) throw new IllegalArgumentException();
        synchronized (mJobServiceListeners) {
            mJobServiceListeners.remove(listener);
        }
    }

    /**
     * 添加任务到工作服务中
     * 使用该方法应该确保工作服务中不存在该标识的任务
     *
     * @param task 需要添加的任务
     */
    public void addTask(final Task task, boolean waitCreateIfNotCreate) {
        if (mJobServiceCreated) {
            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_TASK, task);
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_ADD_TASK);
            mContext.startService(serviceIntent);
        } else {
            if (waitCreateIfNotCreate) eventQueue.add(new Runnable() {
                @Override
                public void run() {
                    addTask(task, false);
                }
            });
        }
    }

    /**
     * 添加任务到工作服务中
     * 使用该方法应该确保工作服务中不存在该标识的任务
     *
     * @param task 需要添加的任务
     */
    public void addTask(final Task task) {
        addTask(task, false);
    }

    /**
     * 移除任务
     *
     * @param taskWhat 需要移除的任务标识
     */
    public void removeTask(final long taskWhat, boolean waitCreateIfNotCreate) {
        if (mJobServiceCreated) {
            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_TASK_WHAT, taskWhat);
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_CANCEL_TASK);
            mContext.startService(serviceIntent);
        } else {
            if (waitCreateIfNotCreate) eventQueue.add(new Runnable() {
                @Override
                public void run() {
                    removeTask(taskWhat, false);
                }
            });
        }
    }

    /**
     * 移除任务
     *
     * @param taskWhat 需要移除的任务标识
     */
    public void removeTask(final long taskWhat) {
        if (mJobServiceCreated) {
            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_TASK_WHAT, taskWhat);
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_CANCEL_TASK);
            mContext.startService(serviceIntent);
        }
    }

    /**
     * 设置自动更新的时间间隔
     * 设置后将会开启自动更新
     *
     * @param interval 间隔时间
     */
    public void setAutoPublishProgressInterval(long interval) {
        initChecker();
        if (mJobServiceCreated) {
            mAutoPublish = true;
            Intent intent = getIntent();
            intent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_AUTOMATIC_UPDATE_PROGRESS);
            intent.putExtra(JobService.EXTRA_AUTOMATIC_UPDATE_PROGRESS, true);
            intent.getLongExtra(JobService.EXTRA_AUTOMATIC_UPDATE_PROGRESS_INTERVAL, interval);
            mContext.startService(intent);
        }

    }

    /**
     * 停止任务
     *
     * @param taskWhat 需要停止的任务
     */
    public void stopTask(long taskWhat) {
        if (mJobServiceCreated) {
            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_PAUSE_TASK);
            serviceIntent.putExtra(JobService.EXTRA_TASK_WHAT, taskWhat);
            mContext.startService(serviceIntent);
        }
    }

    /**
     * 恢复停止的任务
     *
     * @param taskWhat 需要恢复的任务标识
     */
    public void resumeTask(long taskWhat) {
        if (mJobServiceCreated) {
            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_RESUME_TASK);
            serviceIntent.putExtra(JobService.EXTRA_TASK_WHAT, taskWhat);
            mContext.startService(serviceIntent);
        }
    }

    /**
     * 是否自动发布进度
     *
     * @param autoPublishProgress 是否自动发布进度
     */
    public void autoPublish(boolean autoPublishProgress) {
        if (mJobServiceCreated) {
            mAutoPublish = autoPublishProgress;
            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_AUTOMATIC_UPDATE_PROGRESS);
            serviceIntent.putExtra(JobService.EXTRA_AUTOMATIC_UPDATE_PROGRESS, autoPublishProgress);
            serviceIntent.putExtra(JobService.EXTRA_AUTOMATIC_UPDATE_PROGRESS_INTERVAL, JobService.DEFAULT_AUTOMATIC_UPDATE_PROGRESS_INTERVAL);
            mContext.startService(serviceIntent);
        }
    }

    /**
     * 发布一次进度
     */
    public void publishOnceProgress() {
        if (mJobServiceCreated) {
            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_UPDATE_PROGRESS_ONCE);
            mContext.startService(serviceIntent);
        }
    }


    /**
     * 添加执行者工厂
     */
    public void addFactory(String clazz) {
        if (mJobServiceCreated) {
            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_ADD_FACTORY);
            serviceIntent.putExtra(JobService.EXTRA_FACTORY_CLASS_NAME, clazz);
            mContext.startService(serviceIntent);
        }
    }


    protected
    @NonNull
    Intent getIntent() {
        return new Intent(mContext, JobService.class);
    }


    /**
     * 将JobService绑定为前台服务
     *
     * @param id           通知的id
     * @param notification 需要绑定的通知
     */
    public final void startForeground(int id, Notification notification) {
        if (mJobServiceCreated) {
            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_NOTIFICATION, notification);
            serviceIntent.putExtra(JobService.EXTRA_NOTIFY_ID, id);
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_START_FOREGROUND);
            mContext.startService(serviceIntent);
        }
    }

    /**
     * 将JobService从前台服务上解除掉
     *
     * @param removeNotification 解除掉服务的时候是偶移除通知
     */
    public final void stopForeground(boolean removeNotification) {
        if (mJobServiceCreated) {
            Intent serviceIntent = getIntent();
            serviceIntent.putExtra(JobService.EXTRA_REMOVE_NOTIFICATION, removeNotification);
            serviceIntent.putExtra(JobService.EXTRA_ACTION, JobService.ACTION_STOP_FOREGROUND);
            mContext.startService(serviceIntent);
        }
    }


    /**
     * 工作服务监听器
     * 用于监听工作服务的状态和任务的执行状态
     */
    public interface JobServiceListener {

        /**
         * 当服务被创建完成后
         */
        void onServiceCreated();

        /***
         * 当服务被初始化后执行
         */
        void onServiceInitialized();

        /**
         * 当服务销毁后执行
         */
        void onServiceDestroyed();

        /**
         * 当任务执行完成后执行
         *
         * @param task     执行完成的任务
         * @param e        任务执行是否发生了异常，通常情况下，异常不为null则表示执行执行操作失败
         * @param progress 执行的任务的进度
         */
        void onTaskExecuted(Task task, Exception e, Progress progress);

        /**
         * 当任务执行停止后执行
         *
         * @param task 暂停的的任务
         * @param e    停止是否发生了异常，通常情况下，异常不为null则表示执行停止操作失败
         */
        void onTaskStopped(Task task, Exception e);

        /**
         * 当任务恢复后执行
         *
         * @param task 恢复的任务对象
         * @param e    恢复是否发生了异常，通常情况下，异常不为null则表示执行恢复操作失败
         */
        void onTaskResumed(Task task, Exception e);


        /**
         * 当任务被移除后执行
         *
         * @param task 被移除的任务对象
         * @param e    移除任务是否发生了异常，通常情况下，异常不为null则表示执行移除操作失败
         */
        void onTaskRemoved(Task task, Exception e);

        /**
         * 当任务列表被获取到后执行
         *
         * @param tasks 获取到的任务列表
         */
        void onTaskListObtained(ArrayList<Task> tasks);

        /**
         * 当新的进度发布后执行
         *
         * @param progresses 当前的任务的进度情况
         */
        void onProgress(HashMap<Task, Progress> progresses);
    }


    /**
     * 工作服务监听器简单实现
     */
    public static class SimpleJobServiceListener implements JobServiceListener {

        @Override
        public void onServiceCreated() {

        }

        @Override
        public void onServiceInitialized() {

        }

        @Override
        public void onServiceDestroyed() {

        }

        @Override
        public void onTaskExecuted(Task task, Exception e, Progress progress) {

        }

        @Override
        public void onTaskStopped(Task task, Exception e) {

        }

        @Override
        public void onTaskResumed(Task task, Exception e) {

        }

        @Override
        public void onTaskRemoved(Task task, Exception e) {

        }

        @Override
        public void onTaskListObtained(ArrayList<Task> tasks) {

        }

        @Override
        public void onProgress(HashMap<Task, Progress> progresses) {

        }
    }


    /**
     * 广播接收器
     * 主要用于和工作服务进行交互
     */
    private class Receiver extends BroadcastReceiver {

        private static final String TAG = "JobServiceManager$Receiver";

        private final HashMap<Task, Progress> PROGRESS_HASH_MAP = new HashMap<>();

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (DEBUG) ALog.i(TAG, "JobServiceManager Received action " + action);
            if (TextUtils.isEmpty(action)) return;
            if (JobService.BROAD_ACTION_SERVICE_CREATED.equals(action)) {
                mJobServiceCreated = true;
                //服务创建成功
                synchronized (mJobServiceListeners) {
                    for (JobServiceListener listener : mJobServiceListeners)
                        listener.onServiceCreated();
                }
            } else if (JobService.BROAD_ACTION_SERVICE_DESTROYED.equals(action)) {
                mJobServiceCreated = false;
                //服务被销毁后执行
                synchronized (mJobServiceListeners) {
                    for (JobServiceListener listener : mJobServiceListeners)
                        listener.onServiceDestroyed();
                }
            } else if (JobService.BROAD_ACTION_TASK_LIST.equals(action)) {//任务列表获取后执行
                synchronized (mJobServiceListeners) {
                    for (JobServiceListener listener : mJobServiceListeners)
                        listener.onTaskListObtained(intent.<Task>getParcelableArrayListExtra(JobService.EXTRA_TASK_LIST));
                }
            } else if (JobService.BROAD_ACTION_PROGRESS.equals(action)) {
                try {
                    ArrayList<Task> tasks = intent.getParcelableArrayListExtra(JobService.EXTRA_TASK_LIST);
                    ArrayList progresses = intent.getParcelableArrayListExtra(JobService.EXTRA_PROGRESS);
                    if (tasks != null && progresses != null && tasks.size() == progresses.size()) {
                        PROGRESS_HASH_MAP.clear();
                        for (int i = 0; i < progresses.size(); i++) {
                            Task task = tasks.get(i);
                            Progress progress = (Progress) progresses.get(i);
                            if (progress.getTask() == task.getWhat()) {
                                PROGRESS_HASH_MAP.put(task, progress);
                            }
                        }
                        synchronized (mJobServiceListeners) {
                            for (JobServiceListener listener : mJobServiceListeners)
                                listener.onProgress(PROGRESS_HASH_MAP);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (JobService.BROAD_ACTION_REMOVE_RESULT.equals(action)) {//任务移除完成
                try {
                    Task task = intent.getParcelableExtra(JobService.EXTRA_TASK);
                    Exception removeResult = (Exception) intent.getSerializableExtra(JobService.EXTRA_EXCEPTION);
                    synchronized (mJobServiceListeners) {
                        for (JobServiceListener listener : mJobServiceListeners)
                            listener.onTaskRemoved(task, removeResult);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (JobService.BROAD_ACTION_SERVICE_INITIALIZED.equals(action)) {//服务初始化完成
                mJobServiceCreated = true;
                synchronized (mJobServiceListeners) {
                    for (JobServiceListener listener : mJobServiceListeners)
                        listener.onServiceInitialized();
                }
            } else if (JobService.BROAD_ACTION_PAUSE_TASK_RESULT.equals(action)) {//任务停止
                try {
                    Task task = intent.getParcelableExtra(JobService.EXTRA_TASK);
                    Exception stopResult = (Exception) intent.getSerializableExtra(JobService.EXTRA_EXCEPTION);
                    synchronized (mJobServiceListeners) {
                        for (JobServiceListener listener : mJobServiceListeners)
                            listener.onTaskStopped(task, stopResult);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (JobService.BROAD_ACTION_RESUME_RESULT.equals(action)) {//任务恢复完成
                try {
                    Task task = intent.getParcelableExtra(JobService.EXTRA_TASK);
                    Exception resumedResult = (Exception) intent.getSerializableExtra(JobService.EXTRA_EXCEPTION);
                    synchronized (mJobServiceListeners) {
                        for (JobServiceListener listener : mJobServiceListeners)
                            listener.onTaskResumed(task, resumedResult);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (JobService.BROAD_ACTION_TASK_EXECUTED.equals(action)) {//任务执行完成
                try {
                    Task task = intent.getParcelableExtra(JobService.EXTRA_TASK);
                    Progress progress = intent.getParcelableExtra(JobService.EXTRA_PROGRESS);
                    Exception executedResult = (Exception) intent.getSerializableExtra(JobService.EXTRA_EXCEPTION);
                    synchronized (mJobServiceListeners) {
                        for (JobServiceListener listener : mJobServiceListeners)
                            listener.onTaskExecuted(task, executedResult, progress);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
